 #include "slist.h"

//头信息结构体的创建
slist_t *slist_create(int size, op_t my_destroy)
{
    slist_t *s = NULL; 

    //容错判断
    if (size <= 0)
    {
        DEBUG("size <= 0\n"); 
        goto err0;
    }

    //分配空间
    s = malloc(sizeof(slist_t));
    if (NULL == s)
    {
        DEBUG("malloc failed...\n"); 
        goto err0;
    }
    memset(s, 0, sizeof(slist_t));

    //初始化
    s->p = NULL; 
    s->size = size;
    s->count = 0;
    s->my_destroy = my_destroy;

	return s;
err0:
	return NULL;
}


//返回链表中节点的个数
int slist_count(slist_t *s)
{
    //容错判断
    if (NULL == s)
    {
        DEBUG("s is NULL\n"); 
        goto err0;
    }

    //返回节点的个数
    return s->count;
err0:
    return -1;
}

//新分配节点
static void*  __node_malloc(slist_t *s, void *data)
{
    node_t *new = NULL;

    //容错判断
    if (NULL == s || NULL == data) 
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    //分配空间
    new = malloc(sizeof(node_t));
    if (NULL == new)
    {
        DEBUG("malloc failed...\n"); 
        goto err0;
    }
    memset(new, 0, sizeof(node_t));

    //分配数据域空间
    new->data = malloc(s->size);
    if (NULL == new->data)
    {
        DEBUG("malloc failed...\n"); 
        goto err1;
    }
    memset(new->data, 0, s->size);

    //拷贝数据
    memcpy(new->data, data, s->size);
    new->next = NULL;

    s->count ++;

    return new;
err1:
    free(new);
err0:
    return NULL;
}


//头插
int slist_prepend(slist_t *s, void *data)
{
    node_t *new = NULL;

    if (NULL == s || NULL == data)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    //分配新的节点
    new = __node_malloc(s, data);
    if (NULL == new)
    {
        goto err0; 
    }

    //新的节点的后继指向原来的链表的第一个节点
    new->next = s->p;
    //s->p指向新的节点
    s->p = new;

	return 0;
err0:
	return -1;
}

//尾插
int slist_append(slist_t *s, void *data)
{
    //链表节点
    node_t *new = NULL;
    node_t *tmp = NULL;

    //容错判断
    if (NULL == s || NULL == data)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    //分配新节点
    new = __node_malloc(s, data);
    if (NULL == new)
    {
        goto err0; 
    }

    //尾插
    tmp = s->p;

    //没有节点的情况
    if (NULL == s->p)
        s->p = new;
    else
    {
        //tmp指向链表的最后一个节点
        while(NULL != tmp->next)
            tmp = tmp->next;

        tmp->next = new;
    }


	return 0;
err0:
	return -1;
}

//通过索引插入
int slist_insert_by_index(slist_t *s, void *data, int index)
{
    int i = 0;
    node_t *new = NULL;
    node_t *tmp = NULL;

    //容错处理
    if (NULL == s || NULL == data)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    //越界检查
    if (index < 0 || index > s->count)
    {
        DEBUG("The index is out of ranged\n"); 
        goto err0;
    }

    //分配空间
    new = __node_malloc(s, data);
    if (NULL == new)
        goto err0;

    //判断插入的节点为第一个节点的时候
    if (0 == index)
    {
        new->next = s->p;  
        s->p = new;
    }
    else
    {
        //指向第一个节点
        tmp = s->p;
        //找到要插入的位置的上一个节点
        for (i = 0; i < index - 1; i++)
        {
            tmp = tmp->next; 
        }

        new->next = tmp->next;
        tmp->next = new;
    }

    return 0;
err0:
    return -1;
}



//通过索引检索值
int slist_retrieve_by_index(slist_t *s, void *data, int index)
{
    node_t *tmp = NULL;
    int i;
    
    //容错判断
    if (NULL == s || NULL == data)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    //越界检查
    if (index < 0 || index >= s->count)
    {
        DEBUG("The index is out of range\n"); 
        goto err0;
    }

    //指向第一个节点
    tmp = s->p;
    //找到对应索引位置的节点
    for (i = 0; i < index; i++)
    {
        tmp = tmp->next; 
    }

    //拷贝数据
    memcpy(data, tmp->data, s->size);

    return 0;
err0:
    return -1;
}
//通过关键字检索值
int slist_retrieve_by_key(slist_t *s, void *data, void *key, cmp_t my_cmp)
{
    node_t *tmp = NULL;

    //容错判断
    if (NULL == s || NULL == data || NULL == key || NULL == my_cmp)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    //找到对应的节点
    tmp = s->p;
    while(tmp)
    {
        if (my_cmp(tmp->data, key) == 0) 
        {
            //拷贝数据
            memcpy(data, tmp->data, s->size); 
            break;
        }

        tmp = tmp->next;
    }

    //没有找到的情况
    if (tmp == NULL)
        goto err0;

    return 0;
err0:
    return -1;
}


//通过关键字查找索引
int slist_find_index_by_key(slist_t *s, void *key, cmp_t my_cmp)
{
    int index = 0;
    node_t *tmp = NULL;

    //容错判断
    if (NULL == s || NULL == key || NULL == my_cmp)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    tmp = s->p;
    while(NULL != tmp)
    {
        //判断关键子匹配的项
        if (my_cmp(tmp->data, key) == 0) 
        {
            break; 
        }

        tmp = tmp->next;
        index++;
    }
    
    //表示没有找到
    if (NULL == tmp)
        goto err0;

    return index;
err0:
    return -1;
}

//通过关键字查找所有的索引
slist_t *slist_find_all_index_by_key(slist_t *s, void *key, cmp_t my_cmp)
{
    int index = 0;

    node_t *tmp = NULL;
    slist_t *s1 = NULL;

    //容错判断
    if (NULL == s || NULL == key || NULL == my_cmp)
    {
        DEBUG("some elements are NULL\n");      
        goto err0;
    }
    
    //索引值链表
    s1 = slist_create(sizeof(int), NULL);
    if (NULL == s1)
    {
        goto err0; 
    }
    
    //指向第一个节点
    tmp = s->p;

    //遍历链表
    while(NULL != tmp)
    {
        if (my_cmp(tmp->data, key) == 0) 
        {
            slist_append(s1, &index); 
        }

        tmp = tmp->next;
        index ++;
    }

    return s1;
err0:
    return NULL;
}

//通过索引修改对应的结点的数据
int slist_modify_by_index(slist_t *s, void *data, int index)
{
    node_t *tmp  = NULL;

    if (NULL == s || NULL == data)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    if (index < 0 || index >= s->count)
    {
        DEBUG("The index is out of range\n"); 
        goto err0;
    }

    tmp = s->p;

    //找到对应索引的节点
    while(index)
    {
        tmp = tmp->next;
    
        index --; 
    }

    //修改对应的数据域
    memcpy(tmp->data, data, s->size);

    return 0;
err0:
    return -1;
}


//通过关键字修改对应的结点的数据
int slist_modify_by_key(slist_t *s, void *data, void *key, cmp_t op_cmp)
{
    node_t *tmp = NULL;

    if (NULL == s || NULL == data || NULL == key || NULL == op_cmp)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    tmp = s->p;

    //遍历链表
    while(tmp)
    {
        if(op_cmp(tmp->data, key) == 0)
        {
            memcpy(tmp->data, data, s->size); 
            break;
        }
        tmp = tmp->next; 
    }

    return 0;
err0:
    return -1;
}
//功过关键字修改所有的结点的数据
int slist_modify_all_by_key(slist_t *s, void *data, void *key, cmp_t op_cmp)
{
    node_t *tmp = NULL;

    if (NULL == s || NULL == data || NULL == key || NULL == op_cmp)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    tmp = s->p;

    //遍历链表
    while(tmp)
    {
        if(op_cmp(tmp->data, key) == 0)
        {
            memcpy(tmp->data, data, s->size); 
        }
        tmp = tmp->next; 
    }

    return 0;
err0:
    return -1;

}

//通过索引删除链表的结点
int slist_delete_by_index(slist_t *s, int index)
{
    int i = 0;
    node_t *tmp = NULL;
    node_t *save = NULL;

    //容错判断
    if (NULL == s)
    {
        DEBUG("S is NULL\n");  
        goto err0;
    }

    //越界检查
    if (index < 0 || index >= s->count)
    {
        DEBUG("The index is out of range..\n"); 
        goto err0;
    }


    if (0 == index)
    {
        //要删除的节点 用save保存
        save = s->p; 
        //s->p指向下一个节点
        s->p = save->next;
    }
    else
    {
        //tmp指向第一个节点
        tmp = s->p;
        //找到要删除节点的上一个节点
        while(i < index - 1)
        {
            tmp = tmp->next; 
            i++; 
        }

        save = tmp->next;
        //tmp的下一个节点是需要删除的下一个节点
        tmp->next = save->next;
    }

    if (NULL != s->my_destroy)
    {
        s->my_destroy(save->data); 
    }
    free(save->data);
    free(save);

    s->count --;

    return 0;
err0:
    return -1;
}

//通过关键字删除链表的结点
int slist_delete_by_key(slist_t *s, void *key, cmp_t op_cmp)
{
    int index;
    
    if (NULL == s || NULL == key || NULL == op_cmp)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    index = slist_find_index_by_key(s, key, op_cmp);

    slist_delete_by_index(s, index);

    return 0;
err0:
    return -1;
}
//通过关键字删除链表中所有匹配的结点
int slist_delete_all_by_key(slist_t *s, void *key, cmp_t op_cmp)
{
    int i;
    node_t *tmp = NULL;
    node_t *save = NULL;
    
    if (NULL == s || NULL == key || NULL == op_cmp)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    tmp = s->p;
    for (i = 0; i < s->count; i++)
    {
        save = tmp->next;
        if (op_cmp(tmp->data, key) == 0) 
        {
            slist_delete_by_index(s, i); 
            i--;

        }

        tmp = save;
    }
    
    return 0;
err0:
    return -1;
}


//保存链表中的数据到指定的文件中
int slist_store(slist_t *s, const char *path, op_file_t op_store)
{
    int ret = -1;

    node_t *tmp = NULL;
    FILE *fp = NULL;

    //容错判断
    if (NULL == s || NULL == path || NULL == op_store)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    //以写的方式打开一个文件
    fp = fopen(path, "w+"); 
    if (NULL == fp)
    {
        DEBUG("fopen failed...\n"); 
        goto err0;
    }

    //写魔法数字
    ret = fwrite(MAGIC, sizeof(char), strlen(MAGIC), fp);
    if (ret <= 0)
    {
        DEBUG("fwrite magic failed...\n"); 
        goto err1;
    }

    //写大小
    ret = fwrite(&s->size, sizeof(int), 1, fp);
    if (ret <= 0)
    {
        DEBUG("fwrite size failed...\n"); 
        goto err1;
    }

    //写节点的个数
    ret = fwrite(&s->count, sizeof(int), 1, fp);
    if (ret <= 0)
    {
        DEBUG("fwrite count failed...\n"); 
        goto err1;
    }

    tmp = s->p;
    while(NULL != tmp)
    {
        op_store(tmp->data, fp);
         
        tmp = tmp->next; 
    }

    //关闭文件
    fclose(fp);

    return 0;
err1:
    fclose(fp);
err0:
    return -1;
}
//从指定的文件中加载链表的数据
int slist_load(slist_t *s, const char *path, op_file_t op_load)
{
    int ret = -1;
    int count;
    int i;
    char buf[SIZE];
    FILE *fp = NULL;
    void *data = NULL;

    if (NULL == s || NULL == path || NULL == op_load)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    //打开文件
    fp = fopen(path, "r");
    if (NULL == fp)
    {
        DEBUG("fopen failed...\n"); 
        goto err0;
    }
    
    memset(buf, 0, SIZE);
    //读魔法数字
    ret = fread(buf, sizeof(char), strlen(MAGIC), fp);
    if (ret != strlen(MAGIC))
    {
        DEBUG("fread magic failed...\n"); 
        goto err1;
    }
    
    //比较魔法数字
    if (strcmp(buf, MAGIC) != 0)
    {
        DEBUG("file is not matched\n"); 
        goto err1;
    }

    //读取size
    ret = fread(&s->size, sizeof(int), 1, fp);  
    if (ret != 1)
    {
        DEBUG("fread size failed...\n"); 
        goto err1;
    }
    //读取count
    ret = fread(&count, sizeof(int), 1, fp);
    if (ret != 1)
    {
        DEBUG("fread count failed...\n"); 
        goto err1;
    }

    data = malloc(s->size);
    if (NULL == data)
    {
        DEBUG("malloc failed...\n"); 
        goto err1;
    }
    memset(data, 0, s->size);

    //读取数据
    for (i = 0; i < count; i++)
    {
        memset(data, 0, s->size);
        op_load(data, fp);
    
        //尾插
        slist_append(s, data);
    }

    free(data);
    //关闭文件
    fclose(fp);

    return 0;
err1:
    fclose(fp);
err0:
    return -1;
}


//链表的反转
int slist_reverse(slist_t *s)
{
    node_t *tmp = NULL;
    node_t *save = NULL;

    //容错判断
    if (NULL == s)
    {
        DEBUG("s is NULL\n"); 
        goto err0;
    }

    //tmp 指向第一个节点
    tmp = s->p;
    s->p = NULL;

    while(NULL != tmp)
    {
        //保存下一个节点
        save = tmp->next;
        //头插
        tmp->next = s->p;
        //头节点指向tmp tmp作为链表的第一个节点
        s->p = tmp;
        //tmp指向下一个节点
        tmp = save; 
    }
    return 0;
err0:
    return -1;
}

//遍历
int slist_traverse(slist_t *s, op_t my_print)
{
    node_t *tmp = NULL;

    if (NULL == s || NULL == my_print)
    {
        DEBUG("some elements are NULL\n"); 
        goto err0;
    }

    //指向第一个节点
    tmp = s->p;
    while(NULL != tmp)
    {
        my_print(tmp->data); 
        tmp = tmp->next;
    }

	return 0;
err0:
	return -1;
}

//销毁
int slist_destroy(slist_t *s)
{
    node_t *tmp = NULL;
    node_t *save = NULL;

    if (NULL == s)
    {
        DEBUG("s is NULL\n"); 
        goto err0;
    }

    tmp = s->p;

    while(NULL != tmp)
    {
        //保存下一个节点
        save = tmp->next;

        if (NULL != s->my_destroy)
            s->my_destroy(tmp->data);

        //释放数据空间
        free(tmp->data);  

        //释放节点
        free(tmp);
    
        //下一个节点赋值给tmp
        tmp = save;
    }

    //释放头信息结构体
    free(s);

	return 0;
err0:
	return -1;
}





